package redislock

import (
	"context"
	"time"
)

type RedLock struct {
	locks  []*RedisLock
	ttl    time.Duration
	quorum int
}

func NewRedLock(lockerClient []LockClient, key string, expiration time.Duration) (*RedLock, error) {
	locks := make([]*RedisLock, len(lockerClient), len(lockerClient))

	for index, client := range lockerClient {
		if lock, err := New(client, key, expiration); err != nil {
			return nil, err
		} else {
			locks[index] = lock
		}
	}

	return &RedLock{
		locks:  locks,
		quorum: len(lockerClient)/2 + 1,
		ttl:    expiration,
	}, nil
}

func (lock *RedLock) Lock(ctx context.Context) error {
	var successCnt int

	startTime := time.Now()
	for _, l := range lock.locks {
		err := l.Lock(ctx)
		if err == nil {
			successCnt++
		}
	}

	cost := time.Since(startTime)

	if successCnt < lock.quorum || cost > lock.ttl {
		_ = lock.Unlock(ctx)
		return ErrDislockFailed
	}

	return nil
}

func (lock *RedLock) Unlock(ctx context.Context) error {
	var multiErr MultiError // 这是一个自定义的错误类型，可以容纳多个错误

	for _, l := range lock.locks {
		if _err := l.Unlock(ctx); _err != nil {
			multiErr = append(multiErr, _err) // 记录所有的错误
		}
	}

	if len(multiErr) == 0 {
		return nil
	} else {
		return multiErr // 如果有任何错误，都将其返回
	}
}
